﻿using System;
using System.IO;
using System.ComponentModel;
using System.Collections.ObjectModel;
using Uniloader.Configuration;
using Uniloader.Interface;
using System.Collections.Specialized;
using System.Collections.Generic;

namespace Uniloader.Managers
{
    /// <summary>
    /// Abstract interface for a download manager.
    /// </summary>
    public abstract class TransferManager : INotifyCollectionChanged, IEnumerable<TransferTask>, IDisposable
    {
        #region Constructors

        protected TransferManager() : this(null) { }

        protected TransferManager(TransferManagerSection config)
        {
            transferTasks = new ObservableCollection<TransferTask>();
            transferTasks.CollectionChanged += ForwardCollectionChangedEvent;

            dispName = config.DisplayName;

            Initialize();
        } 

        #endregion

        #region Properties

        string dispName;

        /// <summary>
        /// User friendly name of the transfer manager.
        /// </summary>
        public string DisplayName
        {
            get { return dispName; }
        } 

        #endregion

        #region TransferTask collection

        /// <summary>
        /// List containing transfer tasks
        /// </summary>
        private ObservableCollection<TransferTask> transferTasks;

        public void AddTask(TransferTask task)
        {
            if (task == null)
                throw new ArgumentNullException("task");

            if (transferTasks.Contains(task))
                throw new InvalidOperationException("This manager already contains this task.");

            if (task.Manager != null)
                throw new InvalidOperationException("This task was already added to another manager.");

            #region OnAddingTask
            TaskEventArgs args = new TaskEventArgs(task);
            OnAddingTask(args);

            if (args.Cancel)
                return; 
            #endregion

            transferTasks.Add(task);
            task.Manager = this;
        }

        public bool Remove(TransferTask task)
        {
            if (task == null)
                throw new ArgumentNullException("task");

            #region OnRemovingTask
            TaskEventArgs args = new TaskEventArgs(task);
            OnRemovingTask(args); 
            #endregion

            if (args.Cancel)
                return false;
            else if (transferTasks.Remove(task))
            {
                task.Manager = null;

                return true;
            }
            else
                return false;
        }

        public bool Contains(TransferTask task)
        {
            return transferTasks.Contains(task);
        }

        protected virtual void OnAddingTask(TaskEventArgs e)
        {
        }

        protected virtual void OnRemovingTask(TaskEventArgs e)
        {
        }

        #region INotifyCollectionChanged Members

        public event NotifyCollectionChangedEventHandler CollectionChanged;

        private void ForwardCollectionChangedEvent(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (CollectionChanged != null)
                CollectionChanged(this, e);
        }

        #endregion

        #region IEnumerable<TransferTask> Members

        public IEnumerator<TransferTask> GetEnumerator()
        {
            return transferTasks.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return transferTasks.GetEnumerator();
        }

        #endregion 

        #endregion

        #region Initialization/Deinitialization

        /// <summary>
        /// Performs any initialization required by the library.
        /// </summary>
        public abstract void Initialize();

        /// <summary>
        /// Loads previously suspended tasks.
        /// </summary>
        /// <returns>Number of tasks loaded.</returns>
        protected abstract int LoadSuspendedTasks();

        /// <summary>
        /// Writes the task metadata to persistent storage.
        /// </summary>
        protected abstract void PersistTaskMetadata(); 

        #endregion

        #region IDisposable Members

        /// <summary>
        /// Releases all resources used by the TransferManager.
        /// </summary>
        public virtual void Dispose()
        {
        }

        #endregion
    }
}
